/*
 * File:    FileCache.java
 * Created: 19-Nov-2007
 * 
 * by Kenji Hollis <kenji@bitgatesoftware.com>
 * Released under the Creative Commons License version 2.5
 */

package com.bitgate.util.file;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;

import static com.bitgate.util.debug.Debug.debug;
import static com.bitgate.util.debug.Debug.isDebugEnabled;

public class FileCache {
	
	private class FileCacheContainer {
		private byte[] fileData;
		private long lastModified;
		
		public FileCacheContainer(byte[] fileData, long lastModified) {
			this.fileData = fileData;
			this.lastModified = lastModified;
		}
		
		public byte[] getData() {
			return fileData;
		}
		
		public long getModifiedDate() {
			return lastModified;
		}
	}
	
	private final int LRU_CACHE_SIZE = 20;
	private final LinkedHashMap<String, FileCacheContainer> cache;
	private static final FileCache _default = new FileCache();
	
	private FileCache() {
		this.cache = new LinkedHashMap<String, FileCacheContainer>(LRU_CACHE_SIZE);
	}
	
	public static final FileCache getInstance() {
		return _default;
	}
	
	public byte[] getFile(String filename) throws IOException {
		long modifiedDate = (new File(filename)).lastModified();
		FileCacheContainer fcContainer = cache.get(filename);
		
		if (fcContainer != null && fcContainer.getModifiedDate() == modifiedDate) {
			if (isDebugEnabled()) {
				debug("File '" + filename + "' pulled from cache: Size=" + fcContainer.getData().length + " Modification=" +
						fcContainer.getModifiedDate());
			}
			
			return fcContainer.getData();
		}
		
		InputStream is = new FileInputStream(filename);
		
		long length = (new File(filename)).length();
		byte[] dataFile = new byte[(int) length];
		int offset = 0;
		int numRead = 0;
		
        while (offset < dataFile.length && (numRead = is.read(dataFile, offset, dataFile.length - offset)) >= 0) {
             offset += numRead;
        }

        is.close();
        
        fcContainer = new FileCacheContainer(dataFile, modifiedDate);
        
        if (isDebugEnabled()) {
        	debug("File '" + filename + "' added to cache: Size=" + fcContainer.getData().length + " Modification=" +
        			fcContainer.getModifiedDate());
        }
        
        cache.put(filename, fcContainer);
        
        return dataFile;
	}
	
}